﻿using DeHeng_Mes.Model.ConfigModel;
using DeHeng_Mes.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DeHeng_Mes.Utils;
using System.Reflection;
using DeHeng_Mes.Dao.PlcDao;
using DeHeng_Mes.Constant;
using DeHeng_Mes.Model.Singleton;
using SqlSugar;
using MappingTable = DeHeng_Mes.Utils.MappingTable;
using DeHeng_Mes.Model.OrderSingleton;
using S7.Net;
using DeHeng_Mes.Model.PlcModel.door_01;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.Dao;
using NPOI.SS.Formula.Functions;
using System.Text.RegularExpressions;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace DeHeng_Mes.Thread
{
    public class PlcCollectionData
    {
        #region 全局成员
        Dictionary<string, Dictionary<string, bool>> saveStatus = StationSaveStatusDic.SaveStatus;
        List<PlcOrderConfigModel> readPlcList = PlcOrderConfigModelList.ReadPlcList;
        LinePlcToMes LinePlcToMes = new LinePlcToMes();
        PlcDao plcDao = new PlcDao();
        OrderDao orderDao = new OrderDao();
        #endregion

        /// <summary>
        /// Plc交互轮询
        /// </summary>
        /// <returns></returns>
        public async Task CollectionTask()
        {
            int timer = 5000;

            Tools.ProduceLogText("启动Plc交互线程成功！");

            while (true)
            {
                await Task.Delay(timer);

                if (OrderSingleton.GetCount() > 0)
                {
                    timer = 100;
                }

                if (readPlcList?.Count > 0)
                {
                    //遍历订单模型，取出该模型下挂的所有Plc处理数据
                    foreach (var orderModel in readPlcList)
                    {
                        //判断当前订单模型是否处于处理状态，如果处于正在处理状态那么不会继续创建
                        if (!orderModel.Status && orderModel.plc.IsConnected)
                        {
                            // 处理采集数据
                            LinePlcToMes.ProcessOkStatus(orderModel);

                            /*_ = Task.Run(() =>
                            {
                                try
                                {
                                    // 正在处理中
                                    orderModel.Status = true;
                                    // 检查或处理工单前检查当前工单保存状态是否配置
                                    // SaveInit(dictionary, plcModel);

                                    // 处理采集数据
                                    LinePlcToMes.ProcessOkStatus(orderModel);

                                }
                                catch (Exception ex)
                                {
                                    Tools.ProduceLogTextError("数据读取执行失败，原因是：" + ex.Message);
                                }
                                finally
                                {
                                    //处理结束
                                    orderModel.Status = false;
                                }
                            });*/
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 防重码线程
        /// </summary>
        /// <returns></returns>
        public async Task PreventRedundancy()
        {
            Tools.ProduceLogText("防重码线程启动成功!");

            while (true)
            {
                await Task.Delay(100);

                if (readPlcList?.Count > 0)
                {
                    //遍历订单模型，取出该模型下挂的所有Plc处理数据
                    foreach (var orderModel in readPlcList)
                    {
                        //判断当前订单模型是否处于处理状态，如果处于正在处理状态那么不会继续创建
                        if (orderModel.plc.IsConnected)
                        {
                            string station = string.Empty;

                            string logCode = string.Empty;

                            try
                            {
                                // 初始化状态字段
                                string stationStatus = $"{orderModel.PlcName}-STATUS";

                                Tuple<int, int> byteTuple = MappingTable.GetBytesOff(stationStatus);

                                byte[] bytes = orderModel.plc.ReadBytes(DataType.DataBlock, byteTuple.Item1, SystemConstant.ALL_STARTOFF, byteTuple.Item2);

                                // 获取状态字段对应偏移量
                                Dictionary<string, Tuple<int, int>> fieldOffs = MappingTable.GetDicByName(stationStatus);

                                foreach (var fieldOff in fieldOffs)
                                {
                                    // 循环调用方法读取值
                                    string byteData = bytes[fieldOff.Value.Item1].ToString();

                                    if (byteData.Equals("1"))
                                    {
                                        // 获取当前工位的数据偏移量
                                        Dictionary<string, Tuple<int, int>> stationDataOff = MappingTable.GetDicByName(fieldOff.Key); 

                                        // 获取工位对应的数据块
                                        string operation = MappingTable.GetOperationNo(orderModel.PlcName, fieldOff.Key);

                                        // 获取对应工位的已读信号
                                        int off = MappingTable.GetReadOff(fieldOff.Key);

                                        // 获取保存DB信息的二元组
                                        Tuple<int, int> dbTuple = MappingTable.GetBytesOff($"{orderModel.PlcName}-{operation}");

                                        // 读取数组信息
                                        byte[] stationBytes = orderModel.plc.ReadBytes(DataType.DataBlock, dbTuple.Item1, SystemConstant.ALL_STARTOFF, dbTuple.Item2);

                                        // 获取工站过程数据
                                        StationData data = PlcDataUtil.FromBytesToClass(stationBytes, stationDataOff, fieldOff.Key);

                                        if (data != null && data.Code.Count > 0)
                                        {
                                            // 分类批次码与追溯码
                                            foreach (string code in data.Code)
                                            {
                                                station = fieldOff.Key;

                                                logCode = code;

                                                byte status = 7;

                                                if (string.IsNullOrEmpty(code))
                                                    continue;

                                                // 二维码格式校验
                                                status = CodeIsOk(code, orderModel, off);

                                                if (status == 7)
                                                {
                                                    // 防重码
                                                    status = CodePreventRedundancy(code, orderModel, fieldOff.Key);
                                                }

                                                /*if(status == 7)
                                                {
                                                    // 前端框架防跳序

                                                }*/

                                                orderModel.plc.Write(DataType.DataBlock, 5001,orderModel.PlcName.Equals("Rivet") ? off + 2 : off + 4, status);

                                                if (status == 8)
                                                    break;
                                            }
                                        }
                                    }
                                }

                            }
                            catch (Exception ex)
                            {
                                Tools.ProduceLogTextError($"[{station}][{logCode}]防重码线程执行失败，原因是：" + ex.Message );
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 二维码格式校验
        /// </summary>
        /// <param name="data"></param>
        /// <param name="orderModel"></param>
        /// <param name="off"></param>
        private byte CodeIsOk(string code, PlcOrderConfigModel orderModel, int off)
        {
            bool isError = false;

            byte status = 7;

            int ErrorBit = 1000;

            int startErrorOff = 1000;

            try
            {
                (startErrorOff, ErrorBit) = MappingTable.GetErrorOff(orderModel.PlcName,code);
            }
            catch
            {
                isError = true;

                status = 9;
            }

            /*// 正则表达式1：匹配第一种格式 "LAC-51010298 5FK 2A230631 X200001 230831 00001"
            Regex regex1 = new Regex(@"^LAC-\d{8} [A-Z0-9]{3} \d{1}[A-Z]{1}\d{6} [A-Z0-9]{1}\d{6} \d{6} \d{5}$");

            // 正则表达式2：匹配第二种格式 "LAC-56010050 01 5FK 2A230631 X200001 230831 A 00001"
            Regex regex2 = new Regex(@"^LAC-\d{8} \d{2} [A-Z0-9]{3} \d{1}[A-Z]{1}\d{6} [A-Z0-9]{1}\d{6} \d{6} [A-Z] \d{5}$");

            // 正则表达式3：匹配第三种格式 "LAC-84001059 08 240705 A 00001"
            Regex regex3 = new Regex(@"^LAC-\d{8} \d{2} \d{6} [A-Z] \d{5}$");

            // 正则表达式4：匹配第四种格式 "LAC-56010050-1 01 5FK 2A230631 X200001 230831 A 00001"
            Regex regex4 = new Regex(@"^LAC-\d{8}-\d{1} \d{2} [A-Z0-9]{3} \d{1}[A-Z]{1}\d{6} [A-Z0-9]{1}\d{6} \d{6} [A-Z] \d{5}$");*/


            // 正则表达式1：匹配第一种格式 "LAC-51010298 5FK 2A230631 X200001 230831 00001"
            // 修改后：5FK后面有4个字段，每个字段的字符数量保持不变，但不限制内容
            Regex regex1 = new Regex(@"^LAC-\d{8} [A-Z0-9]{3} .{8} .{7} .{6} .{5}$");

            // 正则表达式2：匹配第二种格式 "LAC-56010050 01 5FK 2A230631 X200001 230831 A 00001"
            // 修改后：5FK后面有5个字段，保持字符数量但不限制内容
            Regex regex2 = new Regex(@"^LAC-\d{8} \d{2} [A-Z0-9]{3} .{8} .{7} .{6} .{1} .{5}$");

            // 正则表达式3：匹配第三种格式 "LAC-84001059 08 240705 A 00001"
            // 这个格式中没有"5FK"部分，但5FK位置对应的是日期字段，修改为：
            Regex regex3 = new Regex(@"^LAC-\d{8} \d{2} .{6} .{1} .{5}$");

            // 正则表达式4：匹配第四种格式 "LAC-56010050-1 01 5FK 2A230631 X200001 230831 A 00001"
            // 修改后：5FK后面有5个字段，保持字符数量但不限制内容
            Regex regex4 = new Regex(@"^LAC-\d{8}-\d{1} \d{2} [A-Z0-9]{3} .{8} .{7} .{6} .{1} .{5}$");

            bool a = regex1.IsMatch(code);
            bool b = regex2.IsMatch(code);
            bool c = regex3.IsMatch(code);
            bool d = regex4.IsMatch(code);

            if (!(a || b || c || d))
            {
                // 校验失败
                isError = true;

                status = 8;
            }

            if (orderModel.PlcName.Equals("Rivet"))
            {
                Plc plc = PlcOrderConfigModelList.ReadPlcList.Where(x => x.PlcName.Equals("P5")).Select(x => x.plc).FirstOrDefault();

                if (plc != null)
                {
                    plc.WriteBit(DataType.DataBlock, 75, 264, ErrorBit + 3, isError);
                }
            }
            else
            {
                // 反馈是否重码信号
                orderModel.plc.WriteBit(DataType.DataBlock, 75, 264, ErrorBit + 3, isError);
            }

            return status;
        }

        /// <summary>
        /// 二维码防重
        /// </summary>
        /// <param name="data"></param>
        /// <param name="orderModel"></param>
        /// <param name="off"></param>
        private byte CodePreventRedundancy(string code, PlcOrderConfigModel orderModel, string station)
        {
            bool isError = false;

            byte status = 7;

            int startErrorOff = 1000;

            int ErrorBit = 1000;

            try
            {
                (startErrorOff, ErrorBit) = MappingTable.GetErrorOff(orderModel.PlcName, code);
            }
            catch
            {
                isError = true;

                status = 9;
            }

            List<int> ids = orderDao.CodeIsSave(code);

            if (ids.Count != 0)
            {
                isError = true;

                status = 8;

                // 前端框架判断
                if (!orderDao.CodeIsSave(ids.FirstOrDefault(), station))
                {
                    isError = false;

                    status = 7;
                }
            }

            // 反馈是否重码信号
            if (orderModel.PlcName.Equals("Rivet"))
            {
                Plc plc = PlcOrderConfigModelList.ReadPlcList.Where(x => x.PlcName.Equals("P5")).Select(x => x.plc).FirstOrDefault();

                if (plc != null)
                {
                    plc.WriteBit(DataType.DataBlock, 75, 264, ErrorBit + 3, isError);
                }
            }
            else
            {
                // 反馈是否重码信号
                orderModel.plc.WriteBit(DataType.DataBlock, 75, 264, ErrorBit, isError);
            }

            if (status.ToString().Equals("7"))
            {
                orderDao.BackUpCode(code, station);
            }

            return status;
        }
    }
}
